#include "../../include/offlinedict/DictProducer.h"
#include "../../include/offlinedict/MyLogger.h"

#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

DictProducer::DictProducer(const string &dir, SplitTool &split, Configuration &conf)
    : _dir(dir), _split(split), _conf(conf)
{
    getFile();
}

DictProducer::~DictProducer()
{

}

void DictProducer::buildEnDict()
{
    LogInfo("buildEnDict started");

    // 遍历英文文件
    for (auto &file : _files)
    {
        LogInfo("Processing file: " + file);
        ifstream ifs(file);
        if (!ifs)
        {
            LogError("Failed to open file: " + file);
            return;
        }

        string line;
        while (getline(ifs, line), !ifs.eof())
        {
            // 将所有字符大写字母转换成小写，非字母转换成空格
            for (auto &ch : line)
            {
                if (!isalpha(ch))
                {
                    ch = ' ';
                }
                else if (isupper(ch))
                {
                    ch = tolower(ch);
                }
            }

            istringstream iss(line);
            string word;
            while (iss >> word, !iss.eof())
            {
                // 过滤掉停用词
                if (!_conf.isStopWord(word))
                {
                    ++_dict[word];
                }
            }
        }
        ifs.close();
        LogInfo("Finished processing file: " + file);
    }

    LogInfo("buildEnDict finished");

    mapTransformVec();
    return ;
}

void DictProducer::buildCnDict()
{
    LogInfo("buildCnDict started");

    for (auto &file : _files)
    {
        LogInfo("Processing file: " + file);
        ifstream ifs(file);
        if (!ifs)
        {
            LogError("Failed to open file: " + file);
            return;
        }

        ifs.seekg(0, ios_base::end);
        size_t filesize = ifs.tellg();
        ifs.seekg(0, ios_base::beg);
        char *filestring = new char[filesize + 1]();

        ifs.read(filestring, filesize + 1);
        string text(filestring);
        delete[] filestring;

        vector<string> splitDict = _split.cut(text);

        for (auto &ele : splitDict)
        {
            // 过滤掉停用词
            if (nBytesCode(ele[0]) == 3 && !_conf.isStopWord(ele))
            {
                ++_dict[ele];
            }
        }

        ifs.close();
        LogInfo("Finished processing file: " + file);
    }

    LogInfo("buildCnDict finished");

    mapTransformVec();
    return ;
}

size_t DictProducer::nBytesCode(const char ch)
{
    if (ch & (1 << 7))
    {
        int nBytes = 1;
        for (int idx = 0; idx != 6; ++idx)
        {
            if (ch & (1 << (6 - idx)))
            {
                ++nBytes;
            }
            else
                break;
        }
        return nBytes;
    }
    return 1;
}

void DictProducer::buildIndex()
{
    LogInfo("buildIndex started");

    int i = 0;
    for (auto &ele : _vecDict)
    {
        string word = ele.first;
        size_t charNums = word.size() / nBytesCode(word[0]);
        for (size_t idx = 0, n = 0; n != charNums; n++)
        {
            size_t charLen = nBytesCode(word[idx]);
            string subWord = word.substr(idx, charLen);
            _index[subWord].insert(i);
            idx += charLen ;
        }
        i++;
    }

    LogInfo("buildIndex finished");
    return ;
}

void DictProducer::getFile()
{
    LogInfo("getFile started");

    DIR *pdir = opendir(_dir.c_str());
    if (pdir == nullptr)
    {
        LogError("Failed to open directory: " + _dir);
        return;
    }

    struct dirent *pdirent;
    while ((pdirent = readdir(pdir)) != nullptr)
    {
        // 去掉".."和"."文件
        if (strcmp(pdirent->d_name, "..") != 0 && strcmp(pdirent->d_name, ".") != 0)
        {
            _files.push_back(_dir + "/" + pdirent->d_name);
            LogInfo("Found file: " + pdirent->d_name);
        }
    }

    closedir(pdir);
    LogInfo("getFile finished");
    return ;
}

void DictProducer::storeDict(const string &filepath)
{
    LogInfo("storeDict started");

    ofstream ofs(filepath);
    if (!ofs)
    {
        LogError("Failed to open file for writing: " + filepath);
        return;
    }

    for (auto &ele : _dict)
    {
        ofs << ele.first << " " << ele.second << endl;
    }

    LogInfo("storeDict finished");
    ofs.close();
    return;
}

void DictProducer::storeIndex(const string &filepath)
{
    LogInfo("storeIndex started");

    ofstream ofs(filepath);
    if (!ofs)
    {
        LogError("Failed to open file for writing: " + filepath);
        return;
    }

    for (auto &ele : _index)
    {
        ofs << ele.first << " ";
        auto it = ele.second.begin();
        while (it != ele.second.end())
        {
            ofs << *it << " ";
            ++it;
        }
        ofs << endl;
    }
   
    LogInfo("storeIndex finished");
    ofs.close();
    return;
}

void DictProducer::mapTransformVec()
{
    _vecDict.reserve(_dict.size());
    for(const auto& ele:_dict)
    {
        _vecDict.emplace_back(ele.first,ele.second);
    }
}